package tcp

import (
	"context"
	"errors"
	"log"
	"net"
	"reflect"
	"strconv"
	"time"

	context2 "lgrpc/context"
	"lgrpc/message"
	"lgrpc/serializer"
	"lgrpc/service"
	"lgrpc/stub"
)

const numOfLengthBytes = 8

type Server struct {
	network     string
	addr        string
	services    map[string]*stub.ServerStub
	serializers map[uint8]serializer.Serializer
}

func NewServer(network, addr string) *Server {
	s := &Server{
		network:     network,
		addr:        addr,
		services:    make(map[string]*stub.ServerStub, 16),
		serializers: make(map[uint8]serializer.Serializer, 16),
	}
	s.initSerializer()
	return s
}

func (s *Server) initSerializer() {
	js := &serializer.JsonSerializer{}
	ps := &serializer.ProtoSerializer{}
	s.serializers[js.Code()] = js
	s.serializers[ps.Code()] = ps
}

func (s *Server) RegisterService(service service.Service) {
	s.services[service.Name()] = stub.NewServerStub(service, reflect.ValueOf(service), s.serializers)
}

func (s *Server) Start() error {
	l, err := net.Listen(s.network, s.addr)
	if err != nil {
		return err
	}

	for {
		conn, err := l.Accept()
		if err != nil {
			log.Printf("Failed to accept connection: %v", err)
			continue
		}

		go func(conn net.Conn) {
			if err := s.handleConn(conn); err != nil {
				_ = conn.Close()
			}
		}(conn)
	}
}

func (s *Server) handleConn(conn net.Conn) error {
	for {
		data, err := readConn(conn)
		if err != nil {
			return err
		}

		// 还原调用信息
		req := message.DecodeReq(data)
		if err != nil {
			return err
		}

		ctx := context.Background()
		oneway, ok := req.Meta["one-way"]
		var isOneWayRequest = ok && oneway == "true"
		if isOneWayRequest {
			ctx = context2.CtxWithOneway(ctx)
		}
		var cancel context.CancelFunc
		if deadlineStr, ok := req.Meta["deadline"]; ok {
			if deadline, err := strconv.ParseInt(deadlineStr, 10, 64); err == nil {
				ctx, cancel = context.WithDeadline(ctx, time.UnixMilli(deadline))
			}
		}

		resp, err := s.Invoke(ctx, req)
		if cancel != nil {
			cancel()
		}

		// oneway 请求不需要构造响应
		if isOneWayRequest {
			return nil
		}

		if err != nil {
			resp.Error = []byte(err.Error())
		}

		resp.CalculateHeaderLength()
		resp.CalculateBodyLength()

		if isOneWayRequest {
			return nil
		}

		if _, err = conn.Write(message.EncodeResp(resp)); err != nil {
			return err
		}
	}
}

func (s *Server) Invoke(ctx context.Context, req *message.Request) (*message.Response, error) {
	svc, ok := s.services[req.ServiceName]
	if !ok {
		return nil, errors.New("你要调用的服务不存在")
	}

	if context2.IsOneway(ctx) {
		go func() {
			_, _ = svc.Invoke(ctx, req)
		}()
		return nil, errors.New("lgrpc: 微服务服务端 oneway 请求")
	}

	resp := &message.Response{
		RequestID:  req.RequestID,
		Version:    req.Version,
		Compresser: req.Compresser,
		Serializer: req.Serializer,
	}

	respData, err := svc.Invoke(ctx, req)
	resp.Data = respData
	if err != nil {
		return resp, err
	}

	return resp, nil
}
